/*
 * Copyright 2024 Hangzhou Yingyi Technology Co., Ltd
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifdef CONFIG_PAGING
#include <uk/test.h>
#include <uk/arch/paging.h>
#include <uk/plat/common/bootinfo.h>
#include <uk/plat/paging.h>
#define __PLAT_CMN_ARCH_PAGING_H__
#if defined CONFIG_ARCH_ARM_64
#include <arm/arm64/paging.h>
#elif defined CONFIG_ARCH_X86_64
#include <x86/paging.h>
#else
#error "Architecture not supported by paging API"
#endif


#define MAPPED_DIRECT_OFFSET 0x0000ff8000000000
extern struct ukplat_memregion_desc bpt_unmap_mrd;


/* 确保unmap段正确性 */
UK_TESTCASE(plat_raspi, test_unmap_mrd)
{
	UK_TEST_EXPECT_SNUM_EQ(bpt_unmap_mrd.pbase, 0x1000);
	UK_TEST_EXPECT_SNUM_EQ(bpt_unmap_mrd.vbase, 0x1000);
	UK_TEST_EXPECT_SNUM_EQ(bpt_unmap_mrd.len, 0x40000000-0x1000);
	UK_TEST_EXPECT_SNUM_EQ(bpt_unmap_mrd.flags, UKPLAT_MEMRF_UNMAP);
}
UK_TESTCASE(plat_raspi, test_pt_str)
{
	struct uk_pagetable *pt;
	unsigned long pbase = ukarch_pt_read_base();
	unsigned int lvl;
	int rc;

	pt = ukplat_pt_get_active();
	UK_TEST_EXPECT_SNUM_EQ(pt->pt_pbase, pbase);
	UK_TEST_EXPECT_SNUM_EQ(pt->fa, MAPPED_DIRECT_OFFSET);
	UK_TEST_EXPECT_SNUM_EQ(pbase, pt->pt_vbase-MAPPED_DIRECT_OFFSET);

	unsigned long address = 0x40000000000;
	__pte_t lpte;

	unsigned int level = 0;
	__vaddr_t *pt_vaddr = pt->pt_vbase;
	__pte_t pte;
	int attr;

	//successfully mapped,THIS ADDRESS SHOULD BE NORMAL R/W PERMISSION
	rc = ukplat_page_map(pt, address, 0x3F200000, 1, PAGE_ATTR_PROT_RW, 16);
	UK_TEST_EXPECT_ZERO(rc);



	ukplat_pt_walk(pt, address,
	 &level, pt->pt_vbase, &pte);
	 //NON-S
	attr = pgarch_attr_from_pte(pte, 0);
	UK_TEST_EXPECT_ZERO(attr & PTE_ATTR_SH_MASK);
	// PROT
	UK_TEST_EXPECT_SNUM_EQ(attr & 0x03, 3);
	//device
	UK_TEST_EXPECT_SNUM_EQ(attr & PTE_ATTR_IDX_MASK, DEVICE_nGnRnE);

	//any addr with prot R/W
	level = 0;
	ukplat_pt_walk(pt, __VADDR_ANY, &level,
		pt->pt_vbase, &pte);
	UK_TEST_EXPECT_SNUM_EQ(pgarch_attr_from_pte(pte, 0) & 0x03, 3);

	level = 0;
	ukplat_pt_walk(pt, 0x1000, &level,
	 pt->pt_vbase, &pte);
	 //Normal段
	attr = pgarch_attr_from_pte(pte, 0);
	UK_TEST_EXPECT_SNUM_GT(attr & PTE_ATTR_IDX_MASK, 2);
	UK_TEST_EXPECT_SNUM_EQ(attr & 0x03, 3);

	level = 0;
	ukplat_pt_walk(pt, 0xFF8000000000, &level,
	 pt->pt_vbase, &pte);
	attr = pgarch_attr_from_pte(pte, 0);
	UK_TEST_EXPECT_SNUM_EQ(attr & 0x03, 3);

	level = 0;
	ukplat_pt_walk(pt, 0, &level,
	 pt->pt_vbase, &pte);
	attr = pgarch_attr_from_pte(pte, 0);
	UK_TEST_EXPECT_SNUM_EQ(attr & 0x03, 3);

	//LVL3 l3pt511,DIRECT MAPPING,proving a 4-level pagetable
	__vaddr_t vaddr = (__vaddr_t)  pt->pt_vbase;
	int pteindex;
	__vaddr_t ptvbase = (__vaddr_t)  pt->pt_vbase;

	UK_TEST_EXPECT_SNUM_GT(vaddr, 0xFF8000000000);

	pteindex = PT_Lx_IDX(vaddr, 3);
	UK_TEST_EXPECT_SNUM_EQ(pteindex, 511);
}

/* 注册raspi测试套事件 */
uk_testsuite_plat_prio(plat_raspi, NULL, __UK_PRIO_AFTER_0);
#endif /* CONFIG_PAGING */

